package net.simflow.swf.analyzer.gui.exec.para;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeMap;
import java.util.Vector;

import net.simflow.swf.analyzer.gui.opt.TextOperater;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ControlEditor;
import org.eclipse.swt.custom.TableCursor;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

public class ExecMapSettingComposite extends Composite {
	private final static String REGEX_INT = "[1-9]\\d*";

	private Table tblMain;
	private Text txtWeight;
	private Text txtFind;

	/**
	 * Create the composite.
	 * 
	 * @param parent
	 * @param style
	 */
	public ExecMapSettingComposite(Composite parent, String keyTitle,
			String valueTitle, TreeMap<String, Integer> map,
			final TreeMap<String, Integer> defaultMap) {
		super(parent, SWT.NONE);

		setLayout(new GridLayout(1, false));

		Composite cmpButton = new Composite(this, SWT.NONE);
		GridLayout gl_cmpButton = new GridLayout(14, false);
		gl_cmpButton.marginWidth = 0;
		gl_cmpButton.marginHeight = 0;
		cmpButton.setLayout(gl_cmpButton);
		cmpButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
				1, 1));

		Button btnSelectAll = new Button(cmpButton, SWT.NONE);
		btnSelectAll.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		btnSelectAll.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				for (TableItem item : tblMain.getItems()) {
					item.setChecked(true);
				}
			}
		});
		btnSelectAll.setText("All");

		Button btnDeselectAll = new Button(cmpButton, SWT.NONE);
		btnDeselectAll.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		btnDeselectAll.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				for (TableItem item : tblMain.getItems()) {
					item.setChecked(false);
				}
			}
		});
		btnDeselectAll.setText("Clear");

		Button btnSelectInvert = new Button(cmpButton, SWT.NONE);
		btnSelectInvert.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		btnSelectInvert.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				for (TableItem item : tblMain.getItems()) {
					item.setChecked(!item.getChecked());
				}
			}
		});
		btnSelectInvert.setText("Invert");

		Label line1 = new Label(cmpButton, SWT.SEPARATOR | SWT.VERTICAL);
		GridData gd_line1 = new GridData(SWT.CENTER, SWT.FILL, false, false, 1,
				1);
		gd_line1.heightHint = 20;
		line1.setLayoutData(gd_line1);

		txtWeight = new Text(cmpButton, SWT.BORDER | SWT.RIGHT);
		GridData gd_txtWeight = new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1);
		gd_txtWeight.widthHint = 50;
		txtWeight.setLayoutData(gd_txtWeight);
		txtWeight.setText("1");
		TextOperater.getInstance().addVerify(txtWeight, REGEX_INT, 8);

		Button btnSetWeight = new Button(cmpButton, SWT.NONE);
		btnSetWeight.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		btnSetWeight.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				try {
					for (TableItem item : tblMain.getItems()) {
						if (item.getChecked()) {
							item.setText(2, txtWeight.getText());
						}
					}
					tblMain.getColumn(2).pack();
				} catch (Exception ee) {

				}
			}
		});
		btnSetWeight.setText("Set");

		Button btnDefault = new Button(cmpButton, SWT.NONE);
		btnDefault.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				for (TableItem item : tblMain.getItems()) {
					if (item.getChecked()) {
						item.setText(2,
								String.valueOf(defaultMap.get(item.getText(1))));
					}
				}
				tblMain.getColumn(2).pack();
			}
		});
		btnDefault.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		btnDefault.setText("Default");

		Button btnRandom = new Button(cmpButton, SWT.NONE);
		btnRandom.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int max;
				try {
					max = Integer.valueOf(txtWeight.getText());
				} catch (Exception ee) {
					return;
				}

				Random rnd = new Random();
				for (TableItem item : tblMain.getItems()) {
					if (item.getChecked()) {
						item.setText(2, String.valueOf(rnd.nextInt(max) + 1));
					}
				}
				tblMain.getColumn(2).pack();

			}
		});
		btnRandom.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		btnRandom.setText("Random");

		Button btnMultiple = new Button(cmpButton, SWT.NONE);
		btnMultiple.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int multiple;
				try {
					multiple = Integer.valueOf(txtWeight.getText());

					for (TableItem item : tblMain.getItems()) {
						int c = Integer.valueOf(item.getText(2));
						if (item.getChecked()) {
							item.setText(2, String.valueOf(c * multiple));
						}
					}
					tblMain.getColumn(2).pack();
				} catch (Exception ee) {
					return;
				}
			}
		});
		btnMultiple.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		btnMultiple.setText("Multiple");

		Button btnDivide = new Button(cmpButton, SWT.NONE);
		btnDivide.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int multiple;
				try {
					multiple = Integer.valueOf(txtWeight.getText());

					for (TableItem item : tblMain.getItems()) {
						int c = Integer.valueOf(item.getText(2));
						int a = c / multiple;
						if (a <= 0) {
							a = 1;
						}
						if (item.getChecked()) {
							item.setText(2, String.valueOf(a));
						}
					}
					tblMain.getColumn(2).pack();
				} catch (Exception ee) {
					return;
				}
			}
		});
		btnDivide.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		btnDivide.setText("Divide");

		Label line2 = new Label(cmpButton, SWT.SEPARATOR | SWT.VERTICAL);
		GridData gd_line2 = new GridData(SWT.CENTER, SWT.FILL, false, false, 1,
				1);
		gd_line2.heightHint = 20;
		line2.setLayoutData(gd_line2);

		txtFind = new Text(cmpButton, SWT.BORDER);
		txtFind.setToolTipText("");
		txtFind.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
				1, 1));

		Button btnNext = new Button(cmpButton, SWT.ARROW | SWT.DOWN);
		btnNext.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				String text = txtFind.getText();
				if (text.length() <= 0) {
					txtFind.setFocus();
					return;
				}
				findInTable(tblMain, 1, text, true);
			}
		});
		btnNext.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false,
				1, 1));

		Button btnPrevious = new Button(cmpButton, SWT.ARROW | SWT.UP);
		btnPrevious.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				String text = txtFind.getText();
				if (text.length() <= 0) {
					txtFind.setFocus();
					return;
				}
				findInTable(tblMain, 1, text, false);
			}
		});
		btnPrevious.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));

		tblMain = new Table(this, SWT.BORDER | SWT.CHECK | SWT.FULL_SELECTION);
		addTableEditor(tblMain, new int[] { 2 }, REGEX_INT);
		tblMain.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		tblMain.setHeaderVisible(true);
		tblMain.setLinesVisible(true);

		TableColumn tblclmn0 = new TableColumn(tblMain, SWT.NONE);
		tblclmn0.setResizable(false);
		tblclmn0.setWidth(28);

		TableColumn tblclmn1 = new TableColumn(tblMain, SWT.LEFT);
		tblclmn1.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				switch (tblMain.getSortDirection()) {
				case SWT.UP:
					sortTable(tblMain, 1, SWT.DOWN);
					break;
				case SWT.DOWN:
					sortTable(tblMain, 1, SWT.UP);
					break;
				default:
					sortTable(tblMain, 1, SWT.UP);
				}
			}
		});
		tblclmn1.setText(keyTitle);

		TableColumn tblclmn2 = new TableColumn(tblMain, SWT.RIGHT);
		tblclmn2.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				switch (tblMain.getSortDirection()) {
				case SWT.UP:
					sortTable(tblMain, 2, SWT.DOWN);
					break;
				case SWT.DOWN:
					sortTable(tblMain, 2, SWT.UP);
					break;
				default:
					sortTable(tblMain, 2, SWT.UP);
				}
			}
		});
		tblclmn2.setText(valueTitle);

		if (map == null) {
			return;
		}

		map.comparator();
		for (Entry<String, Integer> en : map.entrySet()) {
			TableItem item = new TableItem(tblMain, SWT.NONE);
			item.setText(new String[] { "", en.getKey(),
					String.valueOf(en.getValue()) });
		}

		tblMain.pack();
		tblMain.getColumns()[1].pack();
		if (tblMain.getColumns()[1].getWidth() > 500) {
			tblMain.getColumns()[1].setWidth(500);
		}
		tblMain.getColumns()[2].pack();
	}

	private void sortTable(final Table table, final int column, final int order) {
		ArrayList<Vector<String>> l = new ArrayList<Vector<String>>();
		HashMap<Vector<String>, Boolean> map = new HashMap<Vector<String>, Boolean>();
		for (TableItem item : table.getItems()) {
			Vector<String> v = new Vector<String>();
			for (int i = 0; i < table.getColumnCount(); i++) {
				v.add(item.getText(i));
			}
			l.add(v);
			map.put(v, item.getChecked());
		}
		Collections.sort(l, new Comparator<Vector<String>>() {
			public int compare(Vector<String> o1, Vector<String> o2) {
				int com;
				try {
					com = Double.valueOf(o1.get(column)).compareTo(
							Double.valueOf(o2.get(column)));
				} catch (Exception e) {
					com = (o1.get(column).compareToIgnoreCase(o2.get(column)));
				}
				switch (order) {
				case SWT.UP:
					return com;
				case SWT.DOWN:
					return -com;
				default:
					return 0;
				}
			}
		});

		table.removeAll();
		for (Vector<String> v : l) {
			TableItem item = new TableItem(table, SWT.NONE);
			String[] a = new String[v.size()];
			v.toArray(a);
			item.setText(a);
			item.setChecked(map.get(v));
		}

		table.setSortColumn(table.getColumn(column));
		table.setSortDirection(order);
	}

	private void addTableEditor(final Table table, final int[] editableColumn,
			final String regex) {

		final TableCursor cursor = new TableCursor(table, SWT.NONE);
		final ControlEditor editor = new ControlEditor(cursor);
		editor.grabHorizontal = true;
		editor.grabVertical = true;

		cursor.addSelectionListener(new SelectionAdapter() {
			TableItem rowX;
			int columnY;

			public void widgetSelected(SelectionEvent e) {
				table.setSelection(new TableItem[] { cursor.getRow() });
				Text ed = (Text) editor.getEditor();
				if (ed != null && !ed.isDisposed()) {
					if (rowX != null) {
						rowX.setText(columnY, ed.getText());
					}
					ed.dispose();
				}

				TableItem row = cursor.getRow();
				int column = cursor.getColumn();

				boolean is = false;
				for (int i : editableColumn) {
					if (i == column) {
						is = true;
						continue;
					}
				}
				if (!is) {
					return;
				}

				final Text text = new Text(cursor, SWT.RIGHT);
				text.setText(row.getText(column));
				text.selectAll();
				TextOperater.getInstance().addVerify(text, regex, 10);
				text.addFocusListener(new FocusListener() {
					@Override
					public void focusGained(FocusEvent e) {

					}

					@Override
					public void focusLost(FocusEvent e) {
						TableItem row = cursor.getRow();
						int column = cursor.getColumn();

						if (text != null && !text.isDisposed()) {
							if (row != null) {
								row.setText(column, text.getText());
							}
							text.dispose();
						}
					}
				});
				text.addKeyListener(new KeyAdapter() {
					public void keyPressed(KeyEvent e) {
						TableItem row = cursor.getRow();
						int column = cursor.getColumn();

						if (e.character == SWT.ESC) {
							text.dispose();
						}

						if (e.character == SWT.CR) {
							save(row, column);
							select(table.getSelectionIndex() + 1, column);
						}

						rowX = row;
						columnY = column;
					}

					private void save(TableItem row, int column) {
						row.setText(column, text.getText());
						text.dispose();
					}

					private void select(int row, int column) {
						if (row >= table.getItemCount() || row < 0) {
							return;
						}
						cursor.setSelection(row, column);
						Event ee = new Event();
						ee.widget = cursor;
						cursor.notifyListeners(SWT.Selection, ee);
					}
				});
				editor.setEditor(text);
				text.setFocus();
			}
		});
	}

	private void findInTable(Table table, int column, String text,
			boolean isNext) {
		int selection = table.getSelectionIndex();

		if (isNext) {
			if (selection < 0 || selection >= table.getItemCount()) {
				selection = -1;
			}
		} else {
			if (selection < 0 || selection >= table.getItemCount()) {
				selection = 1;
			}
		}

		for (int i = 0; i < table.getItemCount(); i++) {
			int pos;
			if (isNext) {
				pos = i + selection + 1;
				pos = (pos >= table.getItemCount()) ? (pos - table
						.getItemCount()) : (pos);
			} else {
				pos = selection - i - 1;
				pos = (pos < 0) ? (pos + table.getItemCount()) : (pos);
			}
			TableItem item = table.getItem(pos);
			if (item.getText(column).contains(text)) {
				table.select(pos);
				table.setTopIndex(pos);
				return;
			}
		}
		MessageBox message = new MessageBox(
				super.getDisplay().getActiveShell(), SWT.ICON_WARNING);
		message.setMessage("Cannot find \"" + text + "\" in the table.");
		message.open();
	}

	protected TreeMap<String, Integer> getResult() {
		TreeMap<String, Integer> map = new TreeMap<String, Integer>();

		for (TableItem item : tblMain.getItems()) {
			try {
				map.put(item.getText(1), Integer.valueOf(item.getText(2)));
			} catch (Exception e) {

			}
		}
		return map;
	}

	@Override
	protected void checkSubclass() {
		// Disable the check that prevents subclassing of SWT components
	}

}
